#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include "cShell.h"
#include "cFifo.h"

#define  ConsoleDBG
#define  CONSOLE_MSG    printf
#define MAX_STRING_SIZE 0x64
uint8_t cmd_buff[CMD_BUF_LEN];
cmd_analyze_T Cmd_analyze;
CMD_MODE_T CmdMode;
APMode_T APMode = APMode_HeadH;
static void ListAllCMD(int argc, void * cmd_arg[]);

/***************************************user  interface************************************/
//只需要修改这个fifo
extern   fifo_t         ConsoleFifo;
#define  CONSOLE_FIFO   ConsoleFifo
/**/
static void RS232Update(int argc, void * cmd_arg[])
{
	// setUpdating(needUpdate);
	// JumpToBoot();
}
static void software_reset(){
	// SW_RESET();
}
/**/
const cmd_list_T cmd_list[] = {
	/*   命令    参数数目    	处理函数        		帮助信息                         */
	{"?",           0,              ListAllCMD,             "Get All Console CMD"},
	{"help",        0,              ListAllCMD,             "Get All Console CMD"},
	{"fwupgrade",   0,              RS232Update,            "upgrade from RS232 Command"},
	{"reboot",      0,              software_reset,         "software reset"},
	// {"version",     0,              product_getVersion,      "get MCU and BT Version"},
	// {"ledtest",     0,              LED_test,                "LED TEST"},
	// {"linesel",     1,              LINE_sel,                "LINE out signal select"},
	// {"linemute",    1,              LINE_mute,              "LINE out Mute"},
	// {"ampmute",     1,              AMP_mute,               "AMP out Mute"},
	// {"standby",     1,              force_standby,           "force in/out standby"},
    // {"getsta",      0,              get_audio_state,           "get line BT AUX system states"},
};

/*****************************************************************************************/

static void ListAllCMD(int argc, void * cmd_arg[]){
	uint8_t i = 0;
	CONSOLE_MSG("-----------------------------------------------------------------------\r\n");
	CONSOLE_MSG("|                         GET ALL CMD                                 |\r\n");
	CONSOLE_MSG("-----------------------------------------------------------------------\r\n");
	for (i = 0; i < sizeof(cmd_list) / sizeof(cmd_list[0]); i++)
	{
		printf("| %-15s | %-49s|\r\n", cmd_list[i].cmd_name, cmd_list[i].help);
		printf("----------------------------------------------------------------------\r\n");
	}
	CONSOLE_MSG("|                         CMD LIST END                                |\r\n");
	CONSOLE_MSG("-----------------------------------------------------------------------\r\n");
}

static bool show2terminal(void){
	unsigned char RecByte;
	static uint8_t *p = cmd_buff;
	static bool exceedCMDLen = false;
	bool valValid = false;
	if (FIFO_Getc(&CONSOLE_FIFO, &RecByte))
	{
		switch (RecByte)
		{
		case 0x02:
			CmdMode = AP_Mode;
			break;
		case 0x1B:
			CmdMode = Ignor_Mode;
			break;
		}
		switch (CmdMode)
		{
		case Ignor_Mode:{
			switch (RecByte)
			{
			case 0x1B:
			case 0x5B:
				break;
			case 0x41:
				CmdMode = Console_Mode;
//				printf("Move up\r\n");
				break;
			case 0x42:
				CmdMode = Console_Mode;
//				printf("Move down\r\n");
				break;
			case 0x43:
				CmdMode = Console_Mode;
//				printf("Move right\r\n");
				break;
			case 0x44:
				CmdMode = Console_Mode;
//				printf("Move left\r\n");
				break;
			default:
				CmdMode = Console_Mode;
				break;
			}

			break;
		}
		case AP_Mode:{
			switch (APMode)
			{
			case APMode_HeadH:
			{
				if (RecByte == 0x02)
				{
					APMode = APMode_HeadL;
				} else
				{
					APMode = APMode_HeadH;
					CmdMode = Console_Mode;
				}
				break;
			}
			case APMode_HeadL:
			{
				if (RecByte == 0x57)
				{
					APMode = APMode_CmdType;
				} else
				{
					APMode = APMode_HeadH;
					CmdMode = Console_Mode;
				}
				break;
			}
			case APMode_CmdType:
			{
				APMode = APMode_Cmd;
				break;
			}
			case APMode_Cmd:
			{

				APMode = APMode_EndH;
				break;
			}
			case APMode_EndH:
			{
				if (RecByte == 0x10)
				{
					APMode = APMode_EndL;
				} else
				{
					APMode = APMode_HeadH;
					CmdMode = Console_Mode;
				}
				break;
			}
			case APMode_EndL:
			{
				if (RecByte == 0x03)
				{
					valValid = true;
				}
				APMode = APMode_HeadH;
				CmdMode = Console_Mode;
				break;
			}
			}
			break;
		}
		case Console_Mode:
		{
			switch (RecByte)
			{
			case '\b':
			{
				if (p != cmd_buff)
				{
#ifdef	ConsoleDBG
					CONSOLE_MSG("%c", 0x08);
					CONSOLE_MSG("%c", 0x20);
					CONSOLE_MSG("%c", 0x08);
#endif
					p--;
					*p = '\0';
					if (p < &cmd_buff[CMD_BUF_LEN])
					{
						exceedCMDLen = false;
					}
				}
				break;
			}
			case '\r':
			{
#ifdef	ConsoleDBG
				CONSOLE_MSG("%c", RecByte);
#endif
				*p = '\r';
				p++;
				*p = '\0';
				break;
			}
			case '\n':
			{
#ifdef	ConsoleDBG
				CONSOLE_MSG("%c", RecByte);
#endif
				if (exceedCMDLen)
				{
					CONSOLE_MSG("command too long\r\n");
				} else
				{
					*p = '\n';
					p++;
					*p = '\0';
					if (cmd_buff[1] == '\0' || cmd_buff[2] == '\0')
						valValid = false;
					else
						valValid = true;
				}
				p = cmd_buff;
				exceedCMDLen = false;
			}
				break;
			default:
			{
#ifdef	ConsoleDBG
				CONSOLE_MSG("%c", RecByte);
#endif
				if (p < &cmd_buff[CMD_BUF_LEN])
				{
					exceedCMDLen = false;
					*p = RecByte;
					p++;
				} else
				{
					exceedCMDLen = true;
				}
				break;
			}
			}
		}
		}
	}
	return valValid;
}
static bool AnalyzeCMD(uint8_t *str){
	bool result = false, spaceFlag = false;
	uint8_t i, j = 0;
	memset(&Cmd_analyze, 0, sizeof(Cmd_analyze));
	Cmd_analyze.argNum = -1;
	for (i = 0; i < strlen((const char *) str); i++)
	{
		if (str[i] == 0x20) //space
		{
			if (spaceFlag)
			{
				if (Cmd_analyze.cmd_arg[Cmd_analyze.argNum][j - 1] != 0x20)
				{
					Cmd_analyze.argNum++;
					Cmd_analyze.cmd_arg[Cmd_analyze.argNum][j] = '\0';
				}
				if (Cmd_analyze.argNum < ARG_NUM && j < ARG_LEN)
				{
					result = true;
					j = 0;
				} else
				{
					result = false;
					CONSOLE_MSG("the num is wrong\r\n");
					break;
				}
			} else
			{
				Cmd_analyze.argexist = true;
				Cmd_analyze.argNum++;
				spaceFlag = true;
				Cmd_analyze.cmd_name[i] = '\0';
			}
			continue;
		} else if (str[i] == '\n' || str[i] == '\r')
		{
			Cmd_analyze.cmd_arg[Cmd_analyze.argNum][j] = '\0';
			break;
		} else
		{
			if (!spaceFlag)
			{
				if (i < CMD_LEN)
				{
					Cmd_analyze.cmd_name[i] = str[i];
					Cmd_analyze.cmd_name[i + 1] = '\0';
					result = true;
				} else
				{
					result = false;
					break;
				}
			} else
			{
				if (i < CMD_BUF_LEN)
				{
					Cmd_analyze.cmd_arg[Cmd_analyze.argNum][j] = str[i];
					j++;
					Cmd_analyze.cmd_arg[Cmd_analyze.argNum][j] = '\0';
					result = true;
				} else
				{
					result = false;
					break;
				}
			}
		}
	}
	return result;
}

static void ConsolHandle(void){
	int kaiqiang_temp[10];
	if (AnalyzeCMD(cmd_buff))
	{
		uint8_t cmd_list_index = 0;
		bool knownCmd = false;
		for (; cmd_list_index < sizeof(cmd_list) / sizeof(cmd_list[0]);
				cmd_list_index++)
		{
			if (0 == strcmp((const char*) cmd_list[cmd_list_index].cmd_name,
							(const char*) Cmd_analyze.cmd_name))
			{
				if ((cmd_list[cmd_list_index].max_args > Cmd_analyze.argNum)
						|| (Cmd_analyze.argNum + 1 == 0))
				{
					void *cmd_arg[ARG_NUM];
					uint8_t i = 0;
					for (i = 0; i < ARG_NUM; i++){
						cmd_arg[i] = Cmd_analyze.cmd_arg[i];
// #ifdef   Para_Str2HEX
// 						ConsoleTxt2hex(cmd_arg[i]);
// #endif
					}

					knownCmd = true;
					cmd_list[cmd_list_index].handle(Cmd_analyze.argNum + 1,
							cmd_arg);
				}
			}
		}
		if (!knownCmd)
			CONSOLE_MSG("Wrong Command\r\n");
	}
}

void ConsoleTask(void){
	if (show2terminal())
	{
		switch(CmdMode)
		{
		case Ignor_Mode:
		{
			break;
		}
		case Console_Mode:
		{
			ConsolHandle();
			break;
		}
		case AP_Mode:
		{

			break;
		}
		}

	}
}

#if 1
/*
 * if you input "2a" to console, the actuall 0x2a will return;
 */
uint8_t ConsoleTxt2hex(uint8_t *data)
{
	uint8_t cmd=0;
	uint8_t len = strlen((const char*)data);
	if(len>1){
		if (data[0] < 0x3A){
			cmd |= (data[0] - 0x30)<<4;
		} else{
			cmd |= (data[0] - 0x57)<<4;
		}
		if (data[1] < 0x3A){
			cmd |=data[1] - 0x30;
		} else{
			cmd |= data[1] - 0x57;
		}
	}else{
		if (data[0] < 0x3A){
			cmd |= (data[0] - 0x30)<<4;
		}else{
			cmd |= (data[0] - 0x57)<<4;
		}
	}
	return cmd;
}
#endif
/***********************************************************************************************/
